package com.spinach.game;

import cn.hutool.core.util.IdUtil;
import com.spinach.game.config.DouDiZhuConfig;
import com.spinach.game.core.Room;
import com.spinach.game.enums.RoomStatus;
import com.spinach.game.hander.WebsocketHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.Epoll;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.stream.ChunkedWriteHandler;
import io.netty.handler.timeout.IdleStateHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.stereotype.Component;

import javax.annotation.PreDestroy;
import java.net.InetSocketAddress;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
@ConditionalOnBean(DouDiZhuConfig.class)
public class WebSocketServer implements InitializingBean {
    @Autowired
    private DouDiZhuConfig douDiZhuConfig;
    @Autowired
    private WebsocketHandler websocketHandler;

    private final EventLoopGroup parentGroup = Epoll.isAvailable() ? new EpollEventLoopGroup() : new NioEventLoopGroup();
    private final EventLoopGroup childGroup = Epoll.isAvailable() ? new EpollEventLoopGroup() : new NioEventLoopGroup();

    /**
     * 资源关闭--在容器销毁是关闭
     */
    @PreDestroy
    public void close() {
        parentGroup.shutdownGracefully();
        childGroup.shutdownGracefully();
    }

    private void createServer() {
        if (douDiZhuConfig.getRoomNumber() <= 0) {
            log.info("斗地主ws服务无房间数量配置信息");
            return;
        }
        for (int i = 0; i < douDiZhuConfig.getRoomNumber(); i++) {
            Room room = new Room();
//            long id = IdUtil.getSnowflake().nextId();
            long id = 1;
            room.setId(id);
            room.setName(String.join("-", "room", String.valueOf(id)));
            room.setRoomStatus(RoomStatus.BLANK);
            room.initPokers();
            douDiZhuConfig.addRoom(room);
        }
        new Thread(null, () -> {
            try {
                ServerBootstrap bootstrap = new ServerBootstrap()
                        .group(parentGroup, childGroup)
                        .channel(Epoll.isAvailable() ? EpollServerSocketChannel.class : NioServerSocketChannel.class)
                        .localAddress(new InetSocketAddress(douDiZhuConfig.getPort()))
                        .childHandler(new ChannelInitializer<SocketChannel>() {
                            @Override
                            protected void initChannel(SocketChannel ch) throws Exception {
                                ch.pipeline()
                                        .addLast(new IdleStateHandler(60 * 30, 0, 0, TimeUnit.SECONDS))
                                        .addLast(new HttpServerCodec())
                                        .addLast(new ChunkedWriteHandler())
                                        .addLast(new HttpObjectAggregator(8192))
                                        .addLast("ws", new WebSocketServerProtocolHandler(douDiZhuConfig.getPath()))
                                        .addLast(websocketHandler);
                            }
                        });
                ChannelFuture f = bootstrap.bind().sync();
                log.info("斗地主ws服务启动成功");
                f.channel().closeFuture().sync();
            } catch (Exception e) {
                log.error("斗地主ws服务启动失败：", e);
                parentGroup.shutdownGracefully();
                childGroup.shutdownGracefully();
            } finally {
                parentGroup.shutdownGracefully();
                childGroup.shutdownGracefully();
            }
        }, "Thread-spinach-game-doudizhu").start();
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        createServer();
    }
}
